bitkeeper revision 1.666 (3ff980d7gcf3e_3nqJ9SkvI1vvfOIw)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 5 Jan 2004 15:20:55 +0000 (15:20 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 5 Jan 2004 15:20:55 +0000 (15:20 +0000)
dev.c, skbuff.h, netdevice.h:
  Fix network packet receive ordering.

xen/include/xeno/netdevice.h
xen/include/xeno/skbuff.h
xen/net/dev.c

index ea7f56e38e743b2f0310d94a5fae45f23958687e..7b1d3d7ea0aabc8634481d78becd2e3b3eb7d557 100644 (file)
@@ -30,7 +30,7 @@
 #include <xeno/if_packet.h>
 #include <xeno/sched.h>
 #include <xeno/interrupt.h>
-
+#include <xeno/skbuff.h>
 #include <asm/atomic.h>
 #include <asm/cache.h>
 #include <asm/byteorder.h>
@@ -41,9 +41,8 @@
 struct vlan_group;
 
 extern struct skb_completion_queues {
-    struct sk_buff *rx; /* Packets received in interrupt context. */
-    unsigned int rx_qlen;
-    struct sk_buff *tx; /* Tx buffers defunct in interrupt context. */
+    struct sk_buff_head rx;  /* Packets received in interrupt context.   */
+    struct sk_buff     *tx;  /* Tx buffers defunct in interrupt context. */
 } skb_queue[NR_CPUS] __cacheline_aligned;
 
 /* Backlog congestion levels */
index ea83a5210fa887324048c333891665b533faaefb..4325deb4ae989fe26e5b0d7b6a6d0d03f9ebf560 100644 (file)
@@ -23,7 +23,6 @@
 #include <asm/system.h>
 #include <asm/atomic.h>
 #include <asm/types.h>
-#include <linux/spinlock.h>
 #include <linux/mm.h>
 #include <xeno/vif.h>
 
@@ -88,9 +87,7 @@ struct sk_buff_head {
     /* These two members must be first. */
     struct sk_buff     * next;
     struct sk_buff     * prev;
-
     __u32              qlen;
-    spinlock_t lock;
 };
 
 #define MAX_SKB_FRAGS 1 /* KAF: was 6 */
@@ -204,7 +201,6 @@ static inline __u32 skb_queue_len(struct sk_buff_head *list_)
 
 static inline void skb_queue_head_init(struct sk_buff_head *list)
 {
-    spin_lock_init(&list->lock);
     list->prev = (struct sk_buff *)list;
     list->next = (struct sk_buff *)list;
     list->qlen = 0;
@@ -215,9 +211,6 @@ static inline void skb_queue_head_init(struct sk_buff_head *list)
  *     @list: list to use
  *     @newsk: buffer to queue
  *
- *     Queue a buffer at the start of a list. This function takes no locks
- *     and you must therefore hold required locks before calling it.
- *
  *     A buffer cannot be placed on two lists at the same time.
  */    
  
@@ -240,9 +233,6 @@ static inline void __skb_queue_head(struct sk_buff_head *list, struct sk_buff *n
  *      @list: list to use
  *      @newsk: buffer to queue
  *
- *      Queue a buffer at the end of a list. This function takes no locks
- *      and you must therefore hold required locks before calling it.
- *
  *      A buffer cannot be placed on two lists at the same time.
  */ 
 
index ac60f125bbf1311dfabe63a77c0cba452076dee5..a20a0ee6cd8f24cd392145657143da0f095e4749 100644 (file)
@@ -582,18 +582,13 @@ int netif_rx(struct sk_buff *skb)
     unsigned long flags;
 
     local_irq_save(flags);
-
-    if ( unlikely(skb_queue[cpu].rx_qlen > 100) )
+    if ( unlikely(skb_queue_len(&skb_queue[cpu].rx) > 100) )
     {
         local_irq_restore(flags);
         perfc_incr(net_rx_congestion_drop);
         return NET_RX_DROP;
     }
-
-    skb->next = skb_queue[cpu].rx;
-    skb_queue[cpu].rx = skb;
-    skb_queue[cpu].rx_qlen++;
-
+    __skb_queue_tail(&skb_queue[cpu].rx, skb);
     local_irq_restore(flags);
 
     __cpu_raise_softirq(cpu, NET_RX_SOFTIRQ);
@@ -604,15 +599,25 @@ int netif_rx(struct sk_buff *skb)
 static void net_rx_action(struct softirq_action *h)
 {
     int offset, cpu = smp_processor_id();
-    struct sk_buff *skb, *nskb;
+    struct sk_buff_head list, *q = &skb_queue[cpu].rx;
+    struct sk_buff *skb;
 
     local_irq_disable();
-    skb = skb_queue[cpu].rx;
-    skb_queue[cpu].rx = NULL;
-    skb_queue[cpu].rx_qlen = 0;
+    /* Code to patch to the private list header is invalid if list is empty! */
+    if ( unlikely(skb_queue_len(q) == 0) )
+    {
+        local_irq_enable();
+        return;
+    }
+    /* Patch the head and tail skbuffs to point at the private list header. */
+    q->next->prev = (struct sk_buff *)&list;
+    q->prev->next = (struct sk_buff *)&list;
+    /* Move the list to our private header. The public header is reinit'ed. */
+    list = *q;
+    skb_queue_head_init(q);
     local_irq_enable();
 
-    while ( skb != NULL )
+    while ( (skb = __skb_dequeue(&list)) != NULL )
     {
         ASSERT(skb->skb_type == SKB_ZERO_COPY);
 
@@ -646,9 +651,7 @@ static void net_rx_action(struct softirq_action *h)
 
         unmap_domain_mem(skb->head);
 
-        nskb = skb->next;
         kfree_skb(skb);
-        skb = nskb;
     }
 }
 
@@ -2336,10 +2339,12 @@ static void make_rx_response(net_vif_t     *vif,
 
 int setup_network_devices(void)
 {
-    int ret;
+    int i, ret;
     extern char opt_ifname[];
 
     memset(skb_queue, 0, sizeof(skb_queue));
+    for ( i = 0; i < smp_num_cpus; i++ )
+        skb_queue_head_init(&skb_queue[i].rx);
 
     /* Actual receive processing happens in softirq context. */
     open_softirq(NET_RX_SOFTIRQ, net_rx_action, NULL);